package com.by.cloud.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.by.cloud.common.BaseContext;
import com.by.cloud.common.PageResult;
import com.by.cloud.constants.PictureFormatConstant;
import com.by.cloud.enums.ReviewStatusEnum;
import com.by.cloud.enums.UserRoleEnum;
import com.by.cloud.exception.BusinessException;
import com.by.cloud.exception.ErrorCode;
import com.by.cloud.exception.ThrowUtils;
import com.by.cloud.mapper.PictureMapper;
import com.by.cloud.model.dto.picture.*;
import com.by.cloud.model.entity.Category;
import com.by.cloud.model.entity.Picture;
import com.by.cloud.model.entity.PictureCategoryTag;
import com.by.cloud.model.entity.Tag;
import com.by.cloud.model.vo.picture.PictureCategoryTagVo;
import com.by.cloud.model.vo.picture.PictureVo;
import com.by.cloud.model.vo.user.UserVo;
import com.by.cloud.service.*;
import com.by.cloud.utils.FileManager;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lzh
 */
@Service
@RequiredArgsConstructor
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture> implements PictureService {

    private final FileManager fileManager;
    private final UserService userService;
    private final PictureCategoryTagService pictureCategoryTagService;
    private final TagService tagService;
    private final CategoryService categoryService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PictureVo uploadPicture(MultipartFile multipartFile, PictureUploadRequest uploadRequest) {
        // 获取当前登录用户的userId
        Long userId = BaseContext.getCurrentId();
        if (userId == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        if (multipartFile == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "上传文件为空");
        }

        //取出图片id 判断是新增还是更新
        Long pictureId = uploadRequest.getId();
        if (pictureId != null) {
            //不为空则说明是更新,查看图片是否存在
            Picture oldPicture = this.lambdaQuery()
                    .eq(Picture::getPicId, pictureId)
                    .one();
            ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR, "图片不存在");
            //仅仅管理员和本人能够编辑图片
            Long pictureUserId = oldPicture.getUserId();
            //判断登录用户是否是管理员
            boolean isAdmin = userService.isAdmin(userId);
            //判断当前登录用户是否上传图片的本人
            boolean isMe = userId.equals(pictureUserId);
            if (!isAdmin && !isMe) {
                //如果不是管理员或者本人。抛出异常
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
            }
        }

        //根据userId划分用户目录
        String uploadPathPrefix = String.format("user/%s", userId);
        UploadPictureResult uploadPictureResult = fileManager.uploadPicture(multipartFile, uploadPathPrefix);

        //封装返回结果
        Picture picture = new Picture();
        picture.setPicWidth(uploadPictureResult.getPicWidth());
        picture.setPicHeight(uploadPictureResult.getPicHeight());
        picture.setPicScale(uploadPictureResult.getPicScale());
        picture.setPicFormat(uploadPictureResult.getPicFormat());
        picture.setPicSize(uploadPictureResult.getPicSize());
        picture.setPicUrl(uploadPictureResult.getUrl());
        picture.setPicName(uploadPictureResult.getPicName());
        picture.setUserId(userId);
        // 如果 pictureId 不为空，表示更新，否则是新增
        if (pictureId != null) {
            //说明是更新，更新补充 id和编辑信息
            picture.setPicId(pictureId);
            picture.setEditTime(LocalDateTime.now());
        }
        //自动填充更新或者新增的审核信息
        fillReviewParams(picture);
        boolean result = this.saveOrUpdate(picture);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "图片上传失败");
        return PictureVo.objToVo(picture);
    }

    @Override
    public PictureVo getPictureVoById(Long picId) {
        Picture picture = this.getById(picId);
        ThrowUtils.throwIf(picture == null, ErrorCode.NOT_FOUND_ERROR);
        PictureVo pictureVo = PictureVo.objToVo(picture);

        // 设置用户信息
        UserVo userVo = userService.getUserById(pictureVo.getUserId());
        pictureVo.setUserVo(userVo);
        return pictureVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePictureById(PictureUpdateDto updateDto) {
        // 获取参数
        Long picId = updateDto.getPicId();
        String picName = updateDto.getPicName();
        String categoryName = updateDto.getCategoryName();
        String introduction = updateDto.getIntroduction();
        List<Long> tagIdList = updateDto.getTagIdList();

        // 校验参数
        ThrowUtils.throwIf(picId == null || picId <= 0, ErrorCode.PARAMS_ERROR, "图片不存在");
        ThrowUtils.throwIf(StringUtils.isAnyBlank(picName, categoryName), ErrorCode.PARAMS_ERROR, "图片名称和分类不能为空");
        ThrowUtils.throwIf(CollUtil.isEmpty(tagIdList), ErrorCode.PARAMS_ERROR, "标签不能为空");

        // 判断修改的分类是否存在
        Category category = categoryService.lambdaQuery()
                .eq(Category::getCategoryName, categoryName)
                .one();
        ThrowUtils.throwIf(category == null, ErrorCode.NOT_FOUND_ERROR, "分类不存在");

        // 判断修改的标签是否存在
        List<Tag> tagList = tagService.lambdaQuery()
                .in(Tag::getTagId, tagIdList)
                .list();
        if (tagList.size() < tagIdList.size()) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "标签不存在");
        }

        // 更新图片信息
        Picture picture = new Picture();
        picture.setPicId(picId);
        picture.setPicName(picName);
        picture.setCategory(categoryName);
        picture.setIntroduction(introduction);
        picture.setEditTime(LocalDateTime.now());
        //自动填充审核信息
        fillReviewParams(picture);
        this.updateById(picture);

        // 删除图片原本关联的分类与标签
        pictureCategoryTagService.lambdaUpdate()
                .eq(PictureCategoryTag::getPictureId, picId)
                .remove();

        // 重新插入图片分类标签关联关系
        List<PictureCategoryTag> pictureCategoryTagList = new ArrayList<>();
        for (Long tagId : tagIdList) {
            PictureCategoryTag pictureCategoryTag = new PictureCategoryTag();
            pictureCategoryTag.setPictureId(picId);
            pictureCategoryTag.setCategoryId(category.getCategoryId());
            pictureCategoryTag.setTagId(tagId);
            pictureCategoryTagList.add(pictureCategoryTag);
        }
        boolean saveRes = pictureCategoryTagService.saveBatch(pictureCategoryTagList);
        ThrowUtils.throwIf(!saveRes, ErrorCode.SYSTEM_ERROR, "操作失败");
        return true;
    }

    @Override
    public PageResult<PictureVo> queryPictureByPage(PicturePageRequest picturePageRequest) {
        // 检测是否有非法输入
        validPicturePageRequest(picturePageRequest);
        //获取图片分页条件
        String picName = picturePageRequest.getPicName();
        String category = picturePageRequest.getCategory();
        String introduction = picturePageRequest.getIntroduction();
        Integer reviewStatus = picturePageRequest.getReviewStatus();
        String reviewMessage = picturePageRequest.getReviewMessage();
        //用户用于搜索的标签集合
        List<Long> tagList = picturePageRequest.getTagIdList();

        // 搜索栏目搜索
        String searchText = picturePageRequest.getSearchText();

        int current = Math.max(picturePageRequest.getCurrent(), 1);
        int size = Math.max(picturePageRequest.getPageSize(), 10);

        IPage<Picture> page = new Page<>(current, size);
        //封装分页条件
        LambdaQueryWrapper<Picture> wrapper = new LambdaQueryWrapper<>();
        // 从多字段中搜索
        if (StrUtil.isNotBlank(searchText)) {
            // 需要拼接查询条件
            wrapper.and(qw -> qw.like(Picture::getPicName, searchText)
                    .or()
                    .like(Picture::getIntroduction, searchText)
            );
        }
        if (CollUtil.isNotEmpty(tagList)) {
            //用户用于搜索的标签集合不为空
            List<PictureCategoryTag> pictureTags = pictureCategoryTagService.listByIds(tagList);
            if (CollUtil.isNotEmpty(pictureTags)) {
                //查询拥有对应标签需要的图片id
                Set<Long> picIds = pictureTags.stream()
                        .map(PictureCategoryTag::getPictureId)
                        .collect(Collectors.toSet());
                wrapper.in(Picture::getPicId, picIds);
            }

        }
        wrapper.like(StrUtil.isNotBlank(picName), Picture::getPicName, picName);
        wrapper.like(StrUtil.isNotBlank(category), Picture::getCategory, category);
        wrapper.like(StrUtil.isNotBlank(introduction), Picture::getIntroduction, introduction);

        //获取当前登录用户 查看是否要求非法查询非审核数据
        UserVo currentUserInfo = userService.getCurrentUserInfo();
        Integer userRole = currentUserInfo.getUserRole();
        int adminValue = UserRoleEnum.ADMIN.getValue();
        if (adminValue != userRole) {
            //普通用户默认查审核通过
            wrapper.eq(Picture::getReviewStatus, ReviewStatusEnum.PASS.getValue());
        } else {
            //如果传入了审核信息或者审核状态，则要求为管理员
            wrapper.eq(reviewStatus != null, Picture::getReviewStatus, reviewStatus);
            wrapper.like(StrUtil.isNotBlank(reviewMessage), Picture::getReviewMessage, reviewMessage);
        }

        // 以创建时间倒序
        wrapper.orderByDesc(Picture::getCreateTime);
        this.page(page, wrapper);

        long total = page.getTotal();
        if (total <= 0) {
            //查询结果为空
            return PageResult.of(0L, Collections.emptyList());
        }
        //查询结果不为空
        List<Picture> pageRecords = page.getRecords();
        List<PictureVo> pictureVoList = pageRecords.stream()
                .map(PictureVo::objToVo)
                .toList();

        // 接着处理图片对应的用户信息
        if (!CollUtil.isEmpty(pictureVoList)) {
            for (PictureVo pictureVo : pictureVoList) {
                Long userId = pictureVo.getUserId();
                UserVo userVo = null;
                userVo = userService.getUserById(userId);
                pictureVo.setUserVo(userVo);
            }
        }
        return PageResult.of(total, pictureVoList);
    }

    @Override
    public PictureCategoryTagVo listPictureCategoryTag() {
        // 创建返回对象
        PictureCategoryTagVo pictureCategoryTagVo = new PictureCategoryTagVo();
        pictureCategoryTagVo.setCategoryNameList(Collections.emptyList());
        pictureCategoryTagVo.setTagNameList(Collections.emptyList());

        // 获取分类名称列表
        List<Category> categoryList = categoryService.list();
        if (CollUtil.isNotEmpty(categoryList)) {
            List<String> categoryNameList = categoryList.stream()
                    .map(Category::getCategoryName)
                    .toList();
            pictureCategoryTagVo.setCategoryNameList(categoryNameList);
        }

        // 获取标签名称列表
        List<Tag> tagList = tagService.list();
        if (CollUtil.isNotEmpty(tagList)) {
            List<String> tagNameList = tagList.stream()
                    .map(Tag::getTagName)
                    .toList();
            pictureCategoryTagVo.setTagNameList(tagNameList);
        }

        return pictureCategoryTagVo;
    }

    @Override
    public boolean reviewByPictureId(PictureReviewRequest reviewRequest) {
        ThrowUtils.throwIf(reviewRequest == null, ErrorCode.PARAMS_ERROR);
        // 获取图片信息并检查是否存在
        Long pictureId = reviewRequest.getPictureId();
        Picture picture = this.getById(pictureId);
        ThrowUtils.throwIf(picture == null, ErrorCode.NOT_FOUND_ERROR, "上传的图片不存在");
        // 判断图片审核状态是否正常
        Integer reviewStatus = reviewRequest.getReviewStatus();
        if (reviewStatus != null && reviewStatus.equals(picture.getReviewStatus())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请勿重复审核");
        }
        //根据请求审核信息进行审核处理
        String reviewMessage = reviewRequest.getReviewMessage();
        Long userId = BaseContext.getCurrentId();
        boolean result = this.lambdaUpdate()
                .eq(Picture::getPicId, pictureId)
                .set(Picture::getReviewerId, userId)
                .set(StrUtil.isNotBlank(reviewMessage), Picture::getReviewMessage, reviewMessage)
                .set(reviewStatus != null, Picture::getReviewStatus, reviewStatus)
                .set(Picture::getReviewTime, LocalDateTime.now())
                .update();
        return result;
    }

    @Override
    public void fillReviewParams(Picture picture) {
        ThrowUtils.throwIf(picture == null, ErrorCode.PARAMS_ERROR);
        Long userId = BaseContext.getCurrentId();
        if (userService.isAdmin(userId)) {
            //如果为管理员，自动过审核
            picture.setReviewerId(userId);
            picture.setReviewMessage("管理员自动通过审核");
            picture.setReviewStatus(ReviewStatusEnum.PASS.getValue());
            picture.setReviewTime(LocalDateTime.now());
        } else {
            //不是管理员，创建更新都是未审核
            picture.setReviewStatus(ReviewStatusEnum.REVIEWING.getValue());
        }
        boolean result = this.updateById(picture);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

    /**
     * 用户分页请求条件检验
     *
     * @param picture 图片请求格式包装
     */
    public void validPicturePageRequest(PicturePageRequest picture) {
        ThrowUtils.throwIf(picture == null, ErrorCode.PARAMS_ERROR);
        HashMap<String, Integer> hashMap = new HashMap<>();
        // 从对象中取值
        String searchText = picture.getSearchText();
        String picFormat = picture.getPicFormat();
        String category = picture.getCategory();
        String introduction = picture.getIntroduction();
        String picName = picture.getPicName();
        List<Long> tagIdList = picture.getTagIdList();

        hashMap.put(JSONUtil.toJsonStr(tagIdList), PictureFormatConstant.PICTURE_TAGS_MAX_LENGTH);
        hashMap.put(searchText, PictureFormatConstant.PICTURE_INTRODUCTION_MAX_LENGTH);
        hashMap.put(picFormat, PictureFormatConstant.PICTURE_FORMAT_MAX_LENGTH);
        hashMap.put(category, PictureFormatConstant.PICTURE_CATEGORY_MAX_LENGTH);
        hashMap.put(introduction, PictureFormatConstant.PICTURE_INTRODUCTION_MAX_LENGTH);
        hashMap.put(picName, PictureFormatConstant.PICTURE_NAME_MAX_LENGTH);
        // 查找数据时参数校验
        if (CollUtil.isEmpty(hashMap)) {
            return;
        }
        hashMap.forEach((key, value) -> {
            if (key != null) {
                ThrowUtils.throwIf(key.length() > value, ErrorCode.URL_TO_LONG, "请求参数过长，长度最大不能超过 " + value);
            }
        });
    }
}




